package com.ruibang.glass.produce.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.constants.RedisKey;
import com.ruibang.glass.common.utils.DataUtils;
import com.ruibang.glass.common.utils.DateUtils;
import com.ruibang.glass.produce.constant.Constants;
import com.ruibang.glass.produce.domain.req.GlassIdTrackReq;
import com.ruibang.glass.produce.domain.resp.GlassIdTrackDetail;
import com.ruibang.glass.produce.entity.GlassBind;
import com.ruibang.glass.produce.feign.QualityApi;
import com.ruibang.glass.produce.mapper.GlassIdTrackMapper;
import com.ruibang.glass.produce.service.GlassIdTrackService;
import com.ruibang.glass.produce.util.ExcelStyleUtils;
import com.teaming.cloud.framework2.autoconfigure.redis.RedisSingleService;
import com.teaming.cloud.framework2.common.model.ResultBody;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * @Author: songJinKang
 * @CreateTime: 2024-03-14  11:01
 * @Description: TODO
 * @Version: 1.0
 */

@Slf4j
@Service
public class GlassIdTrackServiceImpl extends ServiceImpl<GlassIdTrackMapper, GlassBind> implements GlassIdTrackService {

    @Autowired
    private QualityApi qualityApi;

    @Autowired
    private RedisSingleService redisService;

    @Autowired
    @Qualifier("produceThreadPool")
    private Executor executor;

    @Override
    public IPage<GlassBind> pageQuery(GlassIdTrackReq glassIdTrackReq) {
//        newId冷端ID  oldID投入时关联ID  热端ID(根据oldId查询热端玻璃ID)

        //投料时间
        if (glassIdTrackReq.getFeedStartTime() != null && glassIdTrackReq.getFeedDndTime() != null) {
            long end = glassIdTrackReq.getStationDndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            long start = glassIdTrackReq.getStationStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            glassIdTrackReq.setFeedDndTs(end);
            glassIdTrackReq.setFeedStartTs(start);
        }

        //根据横切时间查询
        IPage<GlassBind> iPage = new Page<>();
        if ((glassIdTrackReq.getStationStartTime() != null && glassIdTrackReq.getStationDndTime() != null) || StringUtils.isNotBlank(glassIdTrackReq.getGlassId())) {
            if (glassIdTrackReq.getStationStartTime() != null && glassIdTrackReq.getStationDndTime() != null) {
                long end = glassIdTrackReq.getStationDndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
                long start = glassIdTrackReq.getStationStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
                List<String> hotIds = baseMapper.getHotId(start, end);
                if (CollectionUtils.isNotEmpty(hotIds)) {
                    if (StringUtils.isNotBlank(glassIdTrackReq.getGlassId())) {
                        //包含热端玻璃ID
                        if (hotIds.contains(glassIdTrackReq.getGlassId())) {
                            //获取冷端玻璃ID
                            ResultBody<List<String>> resultBody = qualityApi.getColdGlassId(Collections.singletonList(glassIdTrackReq.getGlassId()));
                            if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
                                glassIdTrackReq.setColdIds(resultBody.getData());
                            }
                        }
                    } else {
                        //获取冷端玻璃ID
                        ResultBody<List<String>> resultBody = qualityApi.getColdGlassId(hotIds);
                        if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
                            glassIdTrackReq.setColdIds(resultBody.getData());
                        }
                    }
                }
            } else {
                //获取冷端玻璃ID
                ResultBody<List<String>> resultBody = qualityApi.getColdGlassId(Collections.singletonList(glassIdTrackReq.getGlassId()));
                if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
                    glassIdTrackReq.setColdIds(resultBody.getData());
                }
            }
            //查询
            final List<GlassBind> data = new CopyOnWriteArrayList<>();
            if (CollectionUtils.isNotEmpty(glassIdTrackReq.getColdIds())) {
                List<List<String>> batch = DataUtils.batch(glassIdTrackReq.getColdIds(), 500);
                List<CompletableFuture<Void>> completableFutureList = new ArrayList<>();
                for (List<String> batchData : batch) {
                    CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
                        GlassIdTrackReq req = new GlassIdTrackReq();
                        BeanUtils.copyProperties(glassIdTrackReq, req);
                        req.setColdIds(batchData);
                        List<GlassBind> glassBindList = baseMapper.query(req);
                        if (CollectionUtils.isNotEmpty(glassBindList)) {
                            data.addAll(glassBindList);
                        }
                    },executor);
                    completableFutureList.add(completableFuture);
                }
                //等待
                for (CompletableFuture<Void> completableFuture : completableFutureList) {
                    completableFuture.join();
                }
                //分页处理
                if (CollectionUtils.isNotEmpty(data)) {
                    if (glassIdTrackReq.getIsPage().equals(Constants.ONE_STR)) {
                        List<GlassBind> pageData = data.stream().sorted(Comparator.comparing(GlassBind::getCreateTime, Comparator.nullsLast(Comparator.reverseOrder())).reversed())
                                .skip((long) (glassIdTrackReq.getPageNo() - 1) * glassIdTrackReq.getPageSize())
                                .limit(glassIdTrackReq.getPageSize())
                                .collect(Collectors.toList());
                        iPage.setTotal(data.size());
                        iPage.setRecords(pageData);
                        iPage.setSize(glassIdTrackReq.getPageSize());
                        iPage.setCurrent(glassIdTrackReq.getPageNo());
                        if (data.size() % glassIdTrackReq.getPageSize() == 0) {
                            iPage.setPages(data.size() / glassIdTrackReq.getPageSize());
                        } else {
                            iPage.setPages((data.size() / glassIdTrackReq.getPageSize()) + 1);
                        }
                    } else {
                        iPage.setTotal(data.size());
                        iPage.setRecords(data);
                        iPage.setSize(glassIdTrackReq.getPageSize());
                        iPage.setCurrent(glassIdTrackReq.getPageNo());
                    }
                }
            }
        } else {
            iPage = baseMapper.pageQuery(new Page<>(glassIdTrackReq.getPageNo(), glassIdTrackReq.getPageSize()), glassIdTrackReq);
        }

        if (CollectionUtils.isNotEmpty(iPage.getRecords())) {
            List<GlassBind> records = iPage.getRecords();
            //根据冷端玻璃ID获取热端玻璃ID
            List<String> coldIds = records.stream().filter(e -> Constants.ZERO_STR.equals(e.getType())).map(GlassBind::getNewId).distinct().collect(Collectors.toList());
            ResultBody<Map<String, String>> resultBody = qualityApi.getColdIdMappingHotId(coldIds);
            if (resultBody != null && resultBody.getData() != null) {
                Map<String, String> coldIdMappingHotId = resultBody.getData();
                for (GlassBind glassBind : records) {
                    if (Constants.ZERO_STR.equals(glassBind.getType())) {
                        String hotId = coldIdMappingHotId.get(glassBind.getNewId());
                        if (StringUtils.isNotBlank(hotId) && hotId.startsWith(Constants.HOT_GLASS_ID_PREFIX)) {
                            glassBind.setGlassId(hotId);
                            //设置横切时间
                            Object timeObj = redisService.hget(RedisKey.HOT_ID_MAPPING_STATION_START_TIME_KEY, hotId);
                            if (timeObj != null && StringUtils.isNotBlank(timeObj.toString())) {
                                glassBind.setStationStartTime(DateUtils.stringToLocalDateTime(timeObj.toString(), com.ruibang.glass.common.constants.Constants.DATE_TIME_FORMATTER_STR));
                            }
                        }
                    } else {
                        glassBind.setGlassId(glassBind.getOldId());
                        //设置横切时间
                        if (StringUtils.isNotBlank(glassBind.getOldId()) && glassBind.getOldId().startsWith(Constants.HOT_GLASS_ID_PREFIX)) {
                            Object timeObj = redisService.hget(RedisKey.HOT_ID_MAPPING_STATION_START_TIME_KEY, glassBind.getOldId());
                            if (timeObj != null && StringUtils.isNotBlank(timeObj.toString())) {
                                glassBind.setStationStartTime(DateUtils.stringToLocalDateTime(timeObj.toString(), com.ruibang.glass.common.constants.Constants.DATE_TIME_FORMATTER_STR));
                            }
                        }
                    }
                }
            }
        }
        return iPage;
    }


    @Override
    public Map<String, List<GlassIdTrackDetail>> getDetail(String glassId, String serialNumber) {
        Map<String, List<GlassIdTrackDetail>> dataMap = new LinkedHashMap<>();
        CompletableFuture<List<GlassIdTrackDetail>> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            if (StringUtils.isNotBlank(serialNumber)) {
                return baseMapper.getSlProductionStationInfo(serialNumber);
            }
            return Collections.emptyList();
        },executor);
        CompletableFuture<List<GlassIdTrackDetail>> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            if (StringUtils.isNotBlank(glassId)) {
                return baseMapper.getBcProductionStation(glassId);
            }
            return Collections.emptyList();
        },executor);
        CompletableFuture.allOf(completableFuture1, completableFuture2).join();
        try {
            dataMap.put(serialNumber, completableFuture1.get());
            dataMap.put(glassId, completableFuture2.get());
        } catch (Exception e) {
            log.error("数据拼接失败：{}", e.getMessage());
        }
        return dataMap;
    }

    @Override
    public void export(GlassIdTrackReq glassIdTrackReq, HttpServletResponse response) {
        glassIdTrackReq.setPageNo(-1);
        glassIdTrackReq.setPageSize(-1);
        glassIdTrackReq.setIsPage(Constants.ZERO_STR);
        IPage<GlassBind> page = this.pageQuery(glassIdTrackReq);
        if (page != null && CollectionUtils.isNotEmpty(page.getRecords())) {
            List<GlassBind> glassBindList = page.getRecords();
            try {
                EasyExcel.write(response.getOutputStream(), GlassBind.class)
                        .registerWriteHandler(ExcelStyleUtils.createTableStyle())
                        .sheet("history_data").doWrite(glassBindList);
            } catch (IOException e) {
                log.error("数据导出失败：{}", e.getMessage());
            }
        }
    }


}
